package db;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import util.StringParser;

public abstract class BaseDBProxy<T extends DBObject> implements DBProxy<T> {
	
	protected abstract String[] getTableColumnNames();
	
	protected abstract T inflate(ResultSet pResultSet) throws SQLException;
	
	protected abstract String getTableName();
	
	protected abstract String[] getRightValues(T pItem);

	@Override
	public List<T> query(DBConnection pConnection, String pWhere) throws SQLException {
		List<T> result = new LinkedList<>();
		
		query(result, pConnection, pWhere);
		
		return result;
	}
	
	/**
	 * pWhere = "account='***' and password='****'"
	 */
	@Override
	public void query(List<T> pResultContainer, DBConnection pConnection, String pWhere) throws SQLException {
		StringBuffer sb = new StringBuffer("SELECT ");
		String[] columnNames = getTableColumnNames();
		for (String column : columnNames) {
			sb.append(column).append(", ");
		}
		sb.delete(sb.length() - 2, sb.length());
		
		sb.append(" FROM " + getTableName() + " WHERE " + pWhere);
				
		ResultSet pResultSet = pConnection.query(sb.toString());
		while (pResultSet.next()) {
			T item = inflate(pResultSet);
			pResultContainer.add(item);
		}
	}
	
	@Override
	public int update(T pNewItem, DBConnection pConnection) throws SQLException {
		StringBuffer sql = new StringBuffer("UPDATE ").append(getTableName()).append(" SET ");
		String[] leftValues = getTableColumnNames();
		String[] rightValues = getRightValues(pNewItem);
		for (int i = 0; i < leftValues.length; i++) {
			sql.append(leftValues[i]).append(" = ").append(rightValues[i]).append(", ");
		}
		sql.delete(sql.length()-2, sql.length());
		sql.append(" WHERE id = " + pNewItem.getId());
		
		return pConnection.update(sql.toString());
	}
	
	@Override
	public T insert(T pNewItem, DBConnection pConnection) throws SQLException {
		StringBuffer sql = new StringBuffer("INSERT INTO ").append(getTableName());
		sql.append(" (");
		appendArray(sql, getTableColumnNames()).append(") VALUES (");
		String values = StringParser.toString(getRightValues(pNewItem), ", ");
		sql.append(values).append(")");
		
		System.out.println(sql);
		pConnection.update(sql.toString());
		
		ResultSet set = pConnection.query("SELECT LAST_INSERT_ID()");
		
		long id = -1;
		if (set.next()) id = set.getLong(1);
		
		T insertedItem = null;
		if (id != -1) {
			insertedItem = query(pConnection, "id=" + id).get(0);
		}
		
		return insertedItem;
	}
	
	/**
	 * 
	 * @param pItem
	 * @param pConnection
	 * @return dropped item count.
	 * @throws SQLException
	 */
	@Override
	public int drop(T pItem, DBConnection pConnection) throws SQLException {
		return pConnection.update("DELETE FROM " + getTableName() + " WHERE id=" + pItem.getId());
	}
	
	/**
	 * pResult.append("value0, value1, value2");
	 * @param pResult
	 * @param pValues
	 */
	private static StringBuffer appendArray(StringBuffer pResult, String[] pValues) {
		for (int i = 0; i < pValues.length; i++) {
			pResult.append(pValues[i]).append(", ");
		}
		
		if (pValues.length > 0) {
			pResult.delete(pResult.length() - 2, pResult.length());
		}
		return pResult;
	}

}
